// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
// This source file is part of the Cangjie project, licensed under Apache-2.0
// with Runtime Library Exception.
//
// See https://cangjie-lang.cn/pages/LICENSE for license information.

#include "NodeCast.h"
#include "Rules/Rule.h"

#include "Rules/MemberAccessMatchRule.h"

using namespace Cangjie::AST;

namespace CangjieMigrator::Rules {

MemberAccessMatchRule::MemberAccessMatchRule(std::string elementName, std::string memberName)
    : elementName(std::move(elementName)), memberName(std::move(memberName))
{}

MatchRule::Type MemberAccessMatchRule::GetType() const
{
    return Type::MemberAccess;
}

std::unique_ptr<ExtractedInfo> MemberAccessMatchRule::ExtractInfo(const Node &node, const PositionRange &range)
{
    if (node.astKind != ASTKind::MEMBER_ACCESS) {
        return nullptr;
    }
    const auto &memberAccess = Cast<ASTKind::MEMBER_ACCESS>(node);

    if (!memberAccess.target) {
        return nullptr;
    }
    const auto &target = *memberAccess.target;

    if (!memberAccess.baseExpr) {
        return nullptr;
    }
    const auto &baseExpr = *memberAccess.baseExpr;

    if (!baseExpr.ty) {
        return nullptr;
    }
    const auto &ty = *baseExpr.ty;

    std::string packageAndIdentifier;
    if (ty.name.empty()) {
        packageAndIdentifier = target.fullPackageName + '.' + ty.String();
    } else {
        packageAndIdentifier = target.fullPackageName + '.' + ty.name;
    }

    const auto memberPositionBegin = memberAccess.GetMacroCallPos(memberAccess.dotPos) + 1;
    return std::make_unique<MemberAccessExtractedInfo>(range, node,
        memberAccess.field,
        packageAndIdentifier,
        PositionRange(memberPositionBegin, range.end));
}

bool MemberAccessMatchRule::MatchConditions(const ExtractedInfo *info)
{
    const auto memberAccessInfo = dynamic_cast<const MemberAccessExtractedInfo *>(info);
    if (!memberAccessInfo) {
        return false;
    }

    if (memberAccessInfo->member != memberName || memberAccessInfo->packageAndIdentifier != elementName) {
        return false;
    }

    return true;
}

std::vector<Actions::Action> MemberAccessMatchRule::GenerateAction(
    UpdateInstance::File &file, const ExtractedInfo &info, const std::string &update, const Rule *rule) const
{
    if (update.empty()) {
        return {};
    }
    const auto i = dynamic_cast<const MemberAccessExtractedInfo &>(info);
    return {Actions::Replace(i.memberPositionRange, update, rule)};
}

std::unique_ptr<MatchRule> MemberAccessMatchRule::TryBuild(const TomlConfig &config)
{
    if (config.title != "MemberAccess") {
        return nullptr;
    }
    GET_VALUE_IF_EMPTY_RETURN_NULL(config, elementName);
    GET_VALUE_IF_EMPTY_RETURN_NULL(config, memberName);
    return std::make_unique<MemberAccessMatchRule>(elementName, memberName);
}

} // namespace CangjieMigrator::Rules
